#include "serverDefines.h"
#include "./logger/logger.h"
#include <stdio.h> /* for FILE, fscanf */
#include <stdlib.h> /* for malloc,free */
#include <string.h> /* for strcmp */
#include <signal.h> /* for sigaction */

enum reTransmitCode {TIMEUP=0, RTT=5, RTO=25, MAXCLIENTS=10, PORT=6911, MAX_PORT_NUMBER=65535};

static const char* RTTKEY =
    {"RTT"
    };
static const char* RTOKEY =
    {"RTO"
    };
static const char* MAXCLIENTSKEY =
    {"MAX_CLIENTS"
    };
static const char* PORTKEY =
    {"PORT"
    };

int definedRTT=RTT;
int definedRTO=RTO;
int definedMaxClients=MAXCLIENTS;
int definedPort=PORT;

char *confPath = {"./"};
char *confFile = {"tftp.conf"};

/**
 * author: Assaf Paz
 * 
 * initializeServerConfiguration
 * 
 * numOfArguments - the amount of arguments in arguments
 * arguments - the command line argumets which can be:
 * 				-RTO n			total time before giving up
 * 				-RTT n			time between retries
 * 				-PORT n     	server port number
 * 				-MAX_CLIENTS	the maximum amount of simoultaneus clients
 * 
 * This function will initialize the server variables, first by reading the default
 * values, then override this values from the configuration file and last override
 * the values with values that were given from the command line.
 */
void initializeServerConfiguration(int numOfArguments, char* arguments[])
{
    FILE* conf = NULL;
    char key[25];
    int value = 0;
    int tokens = 0;
    char *absolutePath = (char*) malloc ((sizeof(confPath)+sizeof(confFile))*sizeof(char));

    sprintf(absolutePath,"%s%s",confPath, confFile);
    if ((conf = fopen(absolutePath,"r"))!=NULL)
    {
        while ((tokens = fscanf(conf,"%s%*[ \t]%d%*[ \t]",key ,&value))!=EOF)
        {
            if(tokens==2)
            {
                if (!strcmp(RTOKEY,key))
                {
                    definedRTO = value;
                }
                else if (!strcmp(RTTKEY,key))
                {
                    definedRTT = value;
                }
                else if (!strcmp(MAXCLIENTSKEY,key))
                {
                    definedMaxClients = value;
                }
                else if (!strcmp(PORTKEY,key))
	            {
	                if (0<value && value <= MAX_PORT_NUMBER)
	                {
	                	definedPort = value;
	                }
	                else
	                {
	                	logMessage("initializeServerConfiguration: Requested port <%d> is out of range", value); 
	                }
	            }
            }
        }
        fclose(conf);
    }
    free(absolutePath);

    while (0<numOfArguments--)
    {
        if (sscanf(arguments[numOfArguments],"-%s",key)!=EOF)
        {
            if (!strcmp(RTOKEY,arguments[numOfArguments]+1))
            {
                sscanf(arguments[numOfArguments+1],"%d", &value);
                definedRTO = value;
            }
            else if (!strcmp(RTTKEY,arguments[numOfArguments]+1))
            {
                sscanf(arguments[numOfArguments+1],"%d", &value);
                definedRTT = value;
            }
            else if (!strcmp(MAXCLIENTSKEY,arguments[numOfArguments]+1))
            {
                sscanf(arguments[numOfArguments+1],"%d", &value);
                definedMaxClients = value;
            }
            else if (!strcmp(PORTKEY,arguments[numOfArguments]+1))
            {
                sscanf(arguments[numOfArguments+1],"%d", &value);
                if (0<value && value <= MAX_PORT_NUMBER)
                {
                	definedPort = value;
                }
                else
                {
                	logMessage("initializeServerConfiguration: Requested port <%d> is out of range", value); 
                }
            }
        }
    }

    logMessage("PORT=<%d>, RTT=<%d>, RTO=<%d>, Max Clients=<%d>\n", definedPort, definedRTT, definedRTO, definedMaxClients );
}

int getRTT()
{
    return definedRTT;
}

int getRTO()
{
    return definedRTO;
}

int getTIMEUP()
{
    return TIMEUP;
}

int getPort()
{
	return definedPort;
}

int getMaxClients()
{
	return definedMaxClients;
}

/**
 * author: Assaf Paz.
 * 
 * setSignalHandler
 * 
 * sig - signal number
 * handler - a pointer to a function to be executed when a signal is caught
 * 
 * map a function to be run when a specific signal was caught
 */
void setSignalHandler(int sig, void (*handler)(int))
{
    struct sigaction act;
    memset (&act, 0, sizeof(act));
    act.sa_handler = handler;
    act.sa_flags = 0;
    if (-1 == sigaction (sig, &act, NULL))
    {
        perror("unable to set handler for signal");
        logMessage("setSignalHandler: unable to set handler for signal\n");
        exit(EXIT_FAILURE);
    }
}
